package com.huahai.service.impl;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huahai.exception.BusinessException;
import com.huahai.exception.ErrorCode;
import com.huahai.mapper.SpaceMapper;
import com.huahai.pojo.dto.space.analyze.*;
import com.huahai.pojo.entity.Picture;
import com.huahai.pojo.entity.Space;
import com.huahai.pojo.entity.User;
import com.huahai.pojo.vo.space.analyze.*;
import com.huahai.service.PictureService;
import com.huahai.service.SpaceAnalyzeService;
import com.huahai.service.SpaceService;
import com.huahai.service.UserService;
import com.huahai.util.ThrowUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 空间分析服务实现类
 *
 * @author huahai
 * @createDate 2025-07-29 13:34:19
 */
@Service
public class SpaceAnalyzeServiceImpl extends ServiceImpl<SpaceMapper, Space> implements SpaceAnalyzeService {

    @Resource
    private UserService userService;

    @Resource
    private SpaceService spaceService;

    @Resource
    private PictureService pictureService;

    /**
     * 空间资源使用分析
     *
     * @param spaceUsageAnalyzeDTO 空间资源使用分析参数
     * @param loginUser            登录用户
     * @return 空间资源使用分析结果
     */
    @Override
    public SpaceUsageAnalyzeVO getSpaceUsageAnalyze(SpaceUsageAnalyzeDTO spaceUsageAnalyzeDTO, User loginUser) {
        // 1. 校验参数
        ThrowUtils.throwIf(spaceUsageAnalyzeDTO == null, ErrorCode.PARAMS_ERROR);
        // 2. 判断当前分析的是否是公开空间
        if (spaceUsageAnalyzeDTO.isQueryPublic() || spaceUsageAnalyzeDTO.isQueryAll()) {
            // 3. 表示查询公共图库或者所有空间
            // 校验用户权限
            checkSpaceAnalyzeAuth(spaceUsageAnalyzeDTO, loginUser);
            // 统计空间资源使用情况
            QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
            queryWrapper.select("picSize");
            // 填补查询条件
            fillSpaceAnalyzeQueryWrapper(spaceUsageAnalyzeDTO, queryWrapper);
            // 为了节省资源，这里采取对单个字段进行查询，而不是对整个对象进行查询
            List<Object> picSizeObjList = pictureService.getBaseMapper().selectObjs(queryWrapper);
            // 转化 long 类型的列表，并计算其总和
            long picSizeSum = picSizeObjList.stream().mapToLong(obj -> (Long) obj).sum();
            long usedCount = picSizeObjList.size();
            // 封装返回结果
            SpaceUsageAnalyzeVO spaceUsageAnalyzeVO = new SpaceUsageAnalyzeVO();
            spaceUsageAnalyzeVO.setUsedSize(picSizeSum);
            spaceUsageAnalyzeVO.setUsedCount(usedCount);
            // 公共图库或者所有空间无上限
            spaceUsageAnalyzeVO.setMaxSize(null);
            spaceUsageAnalyzeVO.setSizeUsageRatio(null);
            spaceUsageAnalyzeVO.setMaxCount(null);
            spaceUsageAnalyzeVO.setCountUsageRatio(null);
            return spaceUsageAnalyzeVO;
        } else {
            // 4. 表示为私人空间
            // 校验权限
            checkSpaceAnalyzeAuth(spaceUsageAnalyzeDTO, loginUser);
            // 获取要查询的空间信息
            Long spaceId = spaceUsageAnalyzeDTO.getSpaceId();
            Space space = spaceService.getById(spaceId);
            Long totalSize = space.getTotalSize();
            Long totalCount = space.getTotalCount();
            Long maxSize = space.getMaxSize();
            Long maxCount = space.getMaxCount();
            // 构造返回结果
            SpaceUsageAnalyzeVO spaceUsageAnalyzeVO = new SpaceUsageAnalyzeVO();
            spaceUsageAnalyzeVO.setUsedSize(totalSize);
            spaceUsageAnalyzeVO.setUsedCount(totalCount);
            spaceUsageAnalyzeVO.setMaxSize(maxSize);
            spaceUsageAnalyzeVO.setMaxCount(maxCount);
            // 后端直接计算好的使用率，前端便于展示
            double sizeUsageRatio = NumberUtil.round(totalSize * 100.0 / maxSize, 2).doubleValue();
            double countUsageRatio = NumberUtil.round(totalCount * 100.0 / maxCount, 2).doubleValue();
            spaceUsageAnalyzeVO.setSizeUsageRatio(sizeUsageRatio);
            spaceUsageAnalyzeVO.setCountUsageRatio(countUsageRatio);
            return spaceUsageAnalyzeVO;
        }
    }

    /**
     * 空间图片分类使用分析
     *
     * @param spaceCategoryAnalyzeDTO 图片分类使用分析参数
     * @param loginUser               登录用户
     * @return 图片分类使用分析结果
     */
    @Override
    public List<SpaceCategoryAnalyzeVO> getSpaceCategoryAnalyze(SpaceCategoryAnalyzeDTO spaceCategoryAnalyzeDTO, User loginUser) {
        // 1. 校验参数
        ThrowUtils.throwIf(spaceCategoryAnalyzeDTO == null, ErrorCode.PARAMS_ERROR);
        // 2. 校验用户权限
        checkSpaceAnalyzeAuth(spaceCategoryAnalyzeDTO, loginUser);
        // 3. 填充查询条件
        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        fillSpaceAnalyzeQueryWrapper(spaceCategoryAnalyzeDTO, queryWrapper);
        // 4. 构造返回结果
        // 4.1 分组查询图片分类
        queryWrapper.select("category AS category",
                        "COUNT(*) AS count",
                        "SUM(picSize) AS totalSize")
                .groupBy("category");
        // 5. 返回分类资源统计结果
        // tips: 只查询需要的字段统计结果， 节省资源开销
        // pictureService.getBaseMapper().selectMaps(queryWrapper)
        return pictureService.getBaseMapper().selectMaps(queryWrapper)
                .stream().map(result -> {
                    // 将查询到的结果进行类型转换
                    String category = result.get("category") != null ? result.get("category").toString() : null;
                    long count = ((Number) result.get("count")).longValue();
                    long totalSize = ((Number) result.get("totalSize")).longValue();
                    return new SpaceCategoryAnalyzeVO(category, count, totalSize);
                }).collect(Collectors.toList());
    }

    /**
     * 空间图片标签使用分析
     *
     * @param spaceTagAnalyzeDTO 图片标签使用分析参数
     * @param loginUser          登录用户
     * @return 图片标签使用分析结果
     */
    @Override
    public List<SpaceTagAnalyzeVO> getSpaceTagAnalyze(SpaceTagAnalyzeDTO spaceTagAnalyzeDTO, User loginUser) {
        // 1. 校验参数
        ThrowUtils.throwIf(spaceTagAnalyzeDTO == null, ErrorCode.PARAMS_ERROR);
        // 2. 校验用户权限
        checkSpaceAnalyzeAuth(spaceTagAnalyzeDTO, loginUser);
        // 3. 填充查询条件
        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("tags");
        fillSpaceAnalyzeQueryWrapper(spaceTagAnalyzeDTO, queryWrapper);
        // 4. 查询符合的图片标签
        // tips: 只查询需要的字段统计结果， 节省资源开销
        List<String> tagJsonList = pictureService.getBaseMapper().selectObjs(queryWrapper)
                .stream()
                // 自动过滤 tags 为空的数据
                .filter(ObjUtil::isNotNull)
                .map(Object::toString)
                .collect(Collectors.toList());

        // 5. 合并所有标签并统计使用次数
        Map<String, Long> tagCountMap = tagJsonList.stream()
                // 将 JSON 字符串转换为列表（扁平化）
                // ["music", "scenery"],["music", "comic"] => "music", "scenery", "music", "comic"
                .flatMap(tagJson -> JSONUtil.toList(tagJson, String.class).stream())
                .collect(Collectors.groupingBy(tag -> tag, Collectors.counting()));

        // 6. 封装成 SpaceTagAnalyzeVO 列表并返回，并根据使用次数降序排列
        return tagCountMap.entrySet().stream()
                // 根据使用次数降序排列
                .sorted((e1, e2) -> Long.compare(e2.getValue(), e1.getValue()))
                .map(entry -> new SpaceTagAnalyzeVO(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList());
    }

    /**
     * 空间图片大小使用分析
     *
     * @param spaceSizeAnalyzeDTO 图片大小使用分析参数
     * @param loginUser           登录用户
     * @return 图片大小使用分析结果
     */
    @Override
    public List<SpaceSizeAnalyzeVO> getSpaceSizeAnalyze(SpaceSizeAnalyzeDTO spaceSizeAnalyzeDTO, User loginUser) {
        // 1. 校验参数
        ThrowUtils.throwIf(spaceSizeAnalyzeDTO == null, ErrorCode.PARAMS_ERROR);
        // 2. 校验用户权限
        checkSpaceAnalyzeAuth(spaceSizeAnalyzeDTO, loginUser);
        // 3. 填充查询条件
        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        fillSpaceAnalyzeQueryWrapper(spaceSizeAnalyzeDTO, queryWrapper);
        // 4. 查询空间符合的图片大小
        // tips: 只查询需要的字段统计结果， 节省资源开销
        queryWrapper.select("picSize");
        List<Long> picSizeList = pictureService.getBaseMapper().selectObjs(queryWrapper)
                .stream()
                // 自动过滤 picSize 为空的数据
                .filter(ObjUtil::isNotNull)
                .map(size -> (Long) size)
                .collect(Collectors.toList());

        // 5. 自定义图片大小的范围，并用有序集合存储
        // 定义分段范围，注意使用有序 Map
        Map<String, Long> sizeRanges = new LinkedHashMap<>();
        sizeRanges.put("<100KB", picSizeList.stream().filter(size -> size < 100 * 1024).count());
        sizeRanges.put("100KB-500KB", picSizeList.stream().filter(size -> size >= 100 * 1024 && size < 500 * 1024).count());
        sizeRanges.put("500KB-1MB", picSizeList.stream().filter(size -> size >= 500 * 1024 && size < 1024 * 1024).count());
        sizeRanges.put(">1MB", picSizeList.stream().filter(size -> size >= 1024 * 1024).count());

        // 6. 封装成响应对象并返回
        return sizeRanges.entrySet()
                .stream()
                .map(entry -> new SpaceSizeAnalyzeVO(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList());
    }

    /**
     * 用户空间上传行为分析
     *
     * @param spaceUserAnalyzeDTO 用户空间上传行为分析参数
     * @param loginUser           登录用户
     * @return 用户空间上传行为分析结果
     */
    @Override
    public List<SpaceUserAnalyzeVO> getSpaceUserAnalyze(SpaceUserAnalyzeDTO spaceUserAnalyzeDTO, User loginUser) {
        // 1. 校验参数
        ThrowUtils.throwIf(spaceUserAnalyzeDTO == null, ErrorCode.PARAMS_ERROR);
        // 2. 校验用户权限
        checkSpaceAnalyzeAuth(spaceUserAnalyzeDTO, loginUser);
        // 3. 填充查询条件
        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        fillSpaceAnalyzeQueryWrapper(spaceUserAnalyzeDTO, queryWrapper);
        // 4. 构造查询条件
        // 4.1 填充用户 id 查询
        Long userId = spaceUserAnalyzeDTO.getUserId();
        if (userId != null && userId > 0) {
            queryWrapper.eq("userId", userId);
        }
        // 4.2 填充时间维度查询 （日， 月， 年）
        String timeDimension = spaceUserAnalyzeDTO.getTimeDimension();
        switch (timeDimension) {
            case "day":
                queryWrapper.select("DATE_FORMAT(createTime, '%Y-%m-%d') AS period", "COUNT(*) AS count");
                break;
            case "week":
                queryWrapper.select("YEARWEEK(createTime) AS period", "COUNT(*) AS count");
                break;
            case "month":
                queryWrapper.select("DATE_FORMAT(createTime, '%Y-%m') AS period", "COUNT(*) AS count");
                break;
            default:
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "不支持的时间维度");
        }
        // 5. 进行分组排序（升序）
        queryWrapper.groupBy("period").orderByAsc("period");
        // 6. 封装成响应对象并返回
        List<Map<String, Object>> userQueryMap = pictureService.getBaseMapper().selectMaps(queryWrapper);
        return userQueryMap.stream()
                .map(result -> {
                    // 构造响应对象
                    String period = result.get("period").toString();
                    long count = ((Number) result.get("count")).longValue();
                    return new SpaceUserAnalyzeVO(period, count);
                }).collect(Collectors.toList());
    }

    /**
     * 用户空间使用量排行分析
     *
     * @param spaceRankAnalyzeDTO 用户空间使用量排行分析参数
     * @param loginUser 登录用户
     * @return 排行前 N 的用户空间信息
     */
    @Override
    public List<Space> getSpaceRankAnalyze(SpaceRankAnalyzeDTO spaceRankAnalyzeDTO, User loginUser) {
        // 1. 校验请求参数
        ThrowUtils.throwIf(spaceRankAnalyzeDTO == null, ErrorCode.PARAMS_ERROR);
        // 2. 校验用户权限 (仅管理员可查看)
        ThrowUtils.throwIf(!userService.isAdmin(loginUser), ErrorCode.NO_AUTH_ERROR);
        // 3. 封装查询前 N 名排行的空间
        QueryWrapper<Space> spaceQueryWrapper = new QueryWrapper<>();
        spaceQueryWrapper.select("id", "spaceName", "userId", "totalSize")
                .orderByDesc("totalSize")
                .last("LIMIT " + spaceRankAnalyzeDTO.getTopN());
        // 4. 返回结果
        return spaceService.list(spaceQueryWrapper);
    }

    /**
     * 空间分析的基本权限校验
     *
     * @param spaceAnalyzeDTO 空间分析参数
     * @param loginUser       登录用户
     */
    @Override
    public void checkSpaceAnalyzeAuth(SpaceAnalyzeDTO spaceAnalyzeDTO, User loginUser) {
        // 1. 校验参数
        boolean isQueryPublic = spaceAnalyzeDTO.isQueryPublic();
        boolean isQueryAll = spaceAnalyzeDTO.isQueryAll();
        // 2. 校验权限
        if (isQueryPublic || isQueryAll) {
            // 全空间分析或者公共图库的分析，需要管理员权限
            ThrowUtils.throwIf(!userService.isAdmin(loginUser), ErrorCode.NO_AUTH_ERROR, "您无此权限");
        } else {
            // 查询指定的空间，需要为空间创建者或者管理员
            Long spaceId = spaceAnalyzeDTO.getSpaceId();
            ThrowUtils.throwIf(spaceId == null || spaceId <= 0, ErrorCode.PARAMS_ERROR);
            Space space = spaceService.getById(spaceId);
            ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR, "空间不存在");
            // 校验权限
            spaceService.checkSpaceAuth(space, loginUser);
        }
    }

    /**
     * 自动填充空间分析参数
     *
     * @param spaceAnalyzeDTO 空间分析参数
     * @param queryWrapper    查询条件
     */
    @Override
    public void fillSpaceAnalyzeQueryWrapper(SpaceAnalyzeDTO spaceAnalyzeDTO, QueryWrapper<Picture> queryWrapper) {
        // 如果查询所有，则不需要填充查询条件
        if (spaceAnalyzeDTO.isQueryAll()) {
            return;
        }
        // 如果查询公共图库，自动过滤有空间 id 的图片
        if (spaceAnalyzeDTO.isQueryPublic()) {
            queryWrapper.isNull("spaceId");
            return;
        }
        // 如果查询个人空间，则需要填充查询条件 spaceId
        Long spaceId = spaceAnalyzeDTO.getSpaceId();
        if (spaceId != null && spaceId > 0) {
            queryWrapper.eq("spaceId", spaceId);
            return;
        }
        // 如果没有指定查询范围，直接抛出异常
        throw new BusinessException(ErrorCode.PARAMS_ERROR, "未指定查询范围");
    }


}




